#include <stdlib.h>

#include "lib.h"

#include "slotguts.h"
#include "slotspin.h"
#include "getrand.h"
#include "sltsql.h"
#include "slotconn.h"
#include "opts.h"
#include "log.h"

#include "jazzguts.h"
#include "jazzslotscommon.h"
using namespace JazzSlotsCommon;

static int32 g_BigBonusPayouts[128] =
{
	//The 128 big bonus payouts, form the big bonus sheet in the worksheet
	//They get one for free, and then a 50/50 shot at any of the next ones being right (up to 4 total). Pick a number from this array for the first one to pay (copied from 'big bonus' sheet in the workbook), and then multiply it by the pick number. For example, if you choose 4, then the wins would be 4 (the one they get for free), 8, 12,  and 16 assuming they got all four.
	22	,
	15	,
	14	,
	13	,
	13	,
	12	,
	12	,
	12	,
	12	,
	12	,
	12	,
	10	,
	9	,
	8	,
	7	,
	7	,
	7	,
	7	,
	7	,
	7	,
	7	,
	7	,
	7	,
	7	,
	7	,
	6	,
	6	,
	6	,
	6	,
	6	,
	6	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	
};


static int32 g_SmallBonusPayouts[128] = 
{
	//The 128 small bonus payouts, from the small bonus sheet in the worksheet
	9	,
	8	,
	7	,
	7	,
	6	,
	6	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	4	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	
};

enum WheelContents {
	BLANK = 0,
	BONGOS,
	BASS,
	TROMBONE,
	SAXOPHONE,
	TRUMPET,
	GUITAR,
	MICROPHONE,
	MARTINI,
	HIHAT,
	SNAREDRUM,
	DRUMSTICKS,
	PIANO,
};


enum SpinResult
{
	EVT_LOSER = 0,

	EVT_SMALLBONUS,
	EVT_BIGBONUS,

	EVT_2BONGOS,
	EVT_2BASS,
	EVT_2TROMBONE,
	EVT_2SAXOPHONE,
	EVT_2TRUMPET,
	EVT_2GUITAR,
	EVT_2MICROPHONE,

	EVT_3BONGOS,
	EVT_3BASS,
	EVT_3TROMBONE,
	EVT_3SAXOPHONE,
	EVT_3TRUMPET,
	EVT_3GUITAR,
	EVT_3MICROPHONE,

	EVT_4BONGOS,
	EVT_4BASS,
	EVT_4TROMBONE,
	EVT_4SAXOPHONE,
	EVT_4TRUMPET,
	EVT_4GUITAR,
	EVT_4MICROPHONE,

	EVT_5BONGOS,
	EVT_5BASS,
	EVT_5TROMBONE,
	EVT_5SAXOPHONE,
	EVT_5TRUMPET,
	EVT_5GUITAR,
	EVT_5MICROPHONE,

	NUMEVENTS
};

SlotSpin *
JazzTimeSlotGuts::makeJackpot()
{
    uint8 *stops = new uint8[getReelCount()];
    SlotSpin *spin = new SlotSpin();

    spin->setBet(0);
    spin->setBonusGameType(0);


    /**
     * Hard set the reels to jackpots.  The assumption is
     * that the jackpot icon is the second to last icon on
     * the strip (the last being a blank).
     */
    for (uint8 i = 0; i < getReelCount(); i++)
    {
        stops[i] = getIcon(i, getIconCount(i) - 2)->position;
    }

    spin->setStops(getReelCount(), stops);

    classifyResult(spin);

    m_spins.push_back(spin);

    delete [] stops;

    return spin;
}




bool8 
JazzTimeSlotGuts::isValidGuts()
{
    return (getGutsId() >= 16400 && getGutsId() < 16500);
}

int32
JazzTimeSlotGuts::getMaxAggregate()
{
    return 56250;
}


uint8
JazzTimeSlotGuts::classifyStops(uint8* stops,uint8 bet, uint8 line)
{
	uint8 result = EVT_LOSER;

	uint8 whichIcon = 0;//BLANK;
	uint8 testIcon = 0;//BLANK;
	bool8 streak = true; //Every line has a streak of at least one

	//Check the first icon (the rest have to match it)
	whichIcon = getIcon(0, stops[0])->iconid;
	testIcon = whichIcon;

	//Now, go through the rest, until the streak is over
	for ( uint8 i = 1; (i < getReelCount())&&(streak); i++ )
    {
		testIcon = getIcon(i, stops[i])->iconid;
		if(testIcon != whichIcon)
		{
			streak = false;
		}
	}
	
	//i is now the number of icons in a row (+1 if streak is false),
	//so pay it out
	if(!streak)
	{
		i-=1;
	}
	switch(i)
	{
		case 2:
			switch(whichIcon)
			{
				case BONGOS:
					result = EVT_2BONGOS;
					break;
				case BASS:
					result = EVT_2BASS;
					break;
				case TROMBONE:
					result = EVT_2TROMBONE;
					break;
				case SAXOPHONE:
					result = EVT_2SAXOPHONE;
					break;
				case TRUMPET:
					result = EVT_2TRUMPET;
					break;
				case GUITAR:
					result = EVT_2GUITAR;
					break;
				case MICROPHONE:
					result = EVT_2MICROPHONE;
					break;

			}
			break;
		case 3:
			switch(whichIcon)
			{
				case BONGOS:
					result = EVT_3BONGOS;
					break;
				case BASS:
					result = EVT_3BASS;
					break;
				case TROMBONE:
					result = EVT_3TROMBONE;
					break;
				case SAXOPHONE:
					result = EVT_3SAXOPHONE;
					break;
				case TRUMPET:
					result = EVT_3TRUMPET;
					break;
				case GUITAR:
					result = EVT_3GUITAR;
					break;
				case MICROPHONE:
					result = EVT_3MICROPHONE;
					break;
			}
			break;
		case 4:
			switch(whichIcon)
			{
				case BONGOS:
					result = EVT_4BONGOS;
					break;
				case BASS:
					result = EVT_4BASS;
					break;
				case TROMBONE:
					result = EVT_4TROMBONE;
					break;
				case SAXOPHONE:
					result = EVT_4SAXOPHONE;
					break;
				case TRUMPET:
					result = EVT_4TRUMPET;
					break;
				case GUITAR:
					result = EVT_4GUITAR;
					break;
				case MICROPHONE:
					result = EVT_4MICROPHONE;
					break;
			}
			break;
		case 5:
			switch(whichIcon)
			{
				case BONGOS:
					result = EVT_5BONGOS;
					break;
				case BASS:
					result = EVT_5BASS;
					break;
				case TROMBONE:
					result = EVT_5TROMBONE;
					break;
				case SAXOPHONE:
					result = EVT_5SAXOPHONE;
					break;
				case TRUMPET:
					result = EVT_5TRUMPET;
					break;
				case GUITAR:
					result = EVT_5GUITAR;
					break;
				case MICROPHONE:
					result = EVT_5MICROPHONE;
					break;
			}
			break;
	}

#if 0
	if (result == EVT_5RING)
	{	
			//Cross Casino Progressive Jackpot
	        this->m_hardMalfunction = true;
	}
#endif

	return result;
}

void
JazzTimeSlotGuts::classifyScatters(SlotSpin *spin)
{
	//Manually traverse through the 15 positions, looking for foodfight or ice cream icons.
	//Three of either is a winner
	uint8 numPianoIcons = 0;
	uint8 numPercussionIcons = 0;
	uint8 PercussionY[3];
	uint8 stop = 0;
	uint8 whichItem = BLANK;
	int32 payout = 0;

	for(int reel = 0; reel<5; reel++)
	{
		for(int row = 0; row < 3; row++)
		{
			stop = relativeWheelPosition(reel, spin->getStops()[reel], row);
			whichItem = getIcon(reel, stop)->iconid;

			//Percussion -> Small Bonus
			if(whichItem >= HIHAT && whichItem <= DRUMSTICKS)
			{
				PercussionY[numPercussionIcons] = row; //We send the client where the pieces are
				numPercussionIcons++;
			}
			//Piano
			else if (whichItem == PIANO)
			{
				numPianoIcons++;
			}
		} //row
	} //reel
	

	//BEGIN FUDGE
	//FUDGE IT FOR NOW
	/*
	numPianoIcons = 3;
	PercussionY[0] = 0;
	PercussionY[1] = 1;
	PercussionY[2] = 2;
	numPercussionIcons = 0;
	*/
	//END FUDGE

	//Set the winners
	if(numPercussionIcons >= 3)
	{
		//If it's icecream, go ahead and play it (we don't need no stinkin' bonus game)
		m_subGame->update(SGIDX_BONUSGAME,	BGCASH);
		m_subGame->update(SGIDX_CASHONEY,	PercussionY[0]);
		m_subGame->update(SGIDX_CASHTWOY,	PercussionY[1]);
		m_subGame->update(SGIDX_CASHTHREEY,	PercussionY[2]);
		payout = getRandomFromArray(g_SmallBonusPayouts, 128)*(spin->getTotalBet());
		m_subGame->update(SGIDX_CASHVALUE,	payout);
		readytofinish = false;
	}
	else if(numPianoIcons >=3)
	{
		//If it's food fight, just set up the targets, and give them the first one as a 'not-picked'
		totalBet = spin->getTotalBet(); //It'll get lost by the time the bonus game play comes back
		m_subGame->update(SGIDX_BONUSGAME,	BGMUSIC);
		initializeGrabBag();
		readytofinish = false;
	}
	else
	{
		m_subGame->update(SGIDX_BONUSGAME,BGNONE);
		readytofinish = true;
	}
}

void
JazzTimeSlotGuts::initializeGrabBag()
{
	//This looks silly, but it avoids the problem of changing sgid order around later:

	//Set the boxes as 'not picked yet'
	m_subGame->update(SGIDX_BBPICKONE,		SGNOTPICKED);
	m_subGame->update(SGIDX_BBPICKTWO,		SGNOTPICKED);
	m_subGame->update(SGIDX_BBPICKTHREE,	SGNOTPICKED);
	m_subGame->update(SGIDX_BBPICKFOUR,		SGNOTPICKED);


	//Set the values as losers
	m_subGame->update(SGIDX_BBVALUEONE,		0);
	m_subGame->update(SGIDX_BBVALUETWO,		0);
	m_subGame->update(SGIDX_BBVALUETHREE,	0);
	m_subGame->update(SGIDX_BBVALUEFOUR,	0);


	//Figure out how many they'll successfully pick
	//They'll always get 1 for free (and the last one is a guaranteed loser)
	//That means, that we just need to pick a random number between 1 and 8.
	//That'll be the number of boxes they get to open:
	m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
	m_subGame->update(SGIDX_NUMGOODPICKS,(getrand() % 4) + 1);
	m_subGame->update(SGIDX_ISDONE, 0);
 
	//We need to put in the spacers
	m_subGame->update(SGIDX_CASHONEY,	0);
	m_subGame->update(SGIDX_CASHTWOY,	0);
	m_subGame->update(SGIDX_CASHTHREEY,	0);
	m_subGame->update(SGIDX_CASHVALUE,	0);
}

void 
JazzTimeSlotGuts::playBonusGame(uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData)
{
	bool8 problem = false;

	if (bonusGameType == 3 && bonusDataCount == 1)
	{
		//we are saving a value for the client
		int32 data = bonusData[0];

		m_subGame->update(SGIDX_CLIENTANIM, data);
		
		createBonusGame(currentGameNum,10,0,3,data,0);

		return;
	}


	if(m_subGame->getData(SGIDX_BONUSGAME)	!=	BGMUSIC)
	{
		//Trying to play when you're not in a bonus game!
		Log::msgWarning("Jazz Time - Not in bonus game: %d", currentGameNum);
		problem = true;
//		m_hardMalfunction = true;
	}


	if(bonusGameType != BGMUSIC)
	{
		//We should only get here with grab bag picks	
		Log::msgWarning("Jazz Time - Wrong bonus game type (%d): %d", bonusGameType, currentGameNum);
		problem = true;

//		ASSERT(0);
//		m_hardMalfunction = true;
	}

	if(bonusDataCount !=1 || (bonusData[0]+4)/4 != 1)
	{
		//We should only have one pick, and it should be between 0 and 3	
		Log::msgWarning("Jazz Time - Funky pick (%d): %d", bonusData[0], currentGameNum);
		problem = true;

	//	ASSERT(0);
	//	m_hardMalfunction = true;
	}

	int32 whichPick = -1;
	int32 whichInstrument = bonusData[0];

	if(!problem)
	{
		if((this->getSlotSpin(this->getSlotSpinCount()-1)) != (SlotSpin *) 0)
		{
			currentGameNum = (this->getSlotSpin(this->getSlotSpinCount()-1))->getGameNum();
			totalBet =(this->getSlotSpin(this->getSlotSpinCount()-1))->getTotalBet();

			//Figure out the payout first, then put it in the right place
			int32 pickValue = getRandomFromArray(g_BigBonusPayouts, 128)*(totalBet);

			//Figure out which (sequential) pick this is (first, second, etc.)
			//We don't use loops, so that we can change the order whenever we'd like
			if(m_subGame->getData(SGIDX_BBPICKONE)==SGNOTPICKED)
			{
				whichPick = 1;
			}
			else if(m_subGame->getData(SGIDX_BBPICKTWO)==SGNOTPICKED)
			{
				whichPick = 2;
			}
			else if(m_subGame->getData(SGIDX_BBPICKTHREE)==SGNOTPICKED)
			{
				whichPick = 3;
			}
			else if(m_subGame->getData(SGIDX_BBPICKFOUR)==SGNOTPICKED)
			{
				whichPick = 4;
			}

			if(whichPick < 0)
			{
				//We've picked way too many
				Log::msgWarning("Jazz Time - Picked too many: %d", currentGameNum);
//				ASSERT(0);
//				m_hardMalfunction = true;
			}


			//If they've picked their limit, then they lose
			if(whichPick > m_subGame->getData(SGIDX_NUMGOODPICKS))
			{
				pickValue = 0; //Loser
				m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true);  /*server only*/
				m_subGame->update(SGIDX_NUMGOODPICKS,0);
				m_subGame->update(SGIDX_ISDONE,1);
				readytofinish = true;
			}
			else
			{
				readytofinish = false;
			}

			//Write out the winner
			switch(whichPick)
			{
				case 1:
					m_subGame->update(SGIDX_BBPICKONE,whichInstrument);
					m_subGame->update(SGIDX_BBVALUEONE,pickValue);
					break;
				case 2:
					m_subGame->update(SGIDX_BBPICKTWO,whichInstrument);
					m_subGame->update(SGIDX_BBVALUETWO,pickValue);
					break;
				case 3:
					m_subGame->update(SGIDX_BBPICKTHREE,whichInstrument);
					m_subGame->update(SGIDX_BBVALUETHREE,pickValue);
					break;
				case 4:
					readytofinish = true;
					m_subGame->update(SGIDX_BBPICKFOUR,whichInstrument);
					m_subGame->update(SGIDX_BBVALUEFOUR,pickValue); //The last one is a guaranteed loser
					m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
					m_subGame->update(SGIDX_NUMGOODPICKS,0);
					m_subGame->update(SGIDX_ISDONE,1);
					break;

			}
    
				//Write to the database
				createBonusGame(currentGameNum,10,whichPick,BGMUSIC,whichInstrument,pickValue*(m_info->creditValue));
				//If we're done, finish the game
				if(isGameComplete())
				{
					completeGame();
				}		
		}
		else //can't load spin
		{
			Log::msgWarning("Jazz Time - Can't load spin data: %d", bonusData[0], currentGameNum);

//			m_hardMalfunction = true;
		}
	}
}


bool8 
JazzTimeSlotGuts::isGameComplete()
{
    return readytofinish;
}



bool8	
JazzTimeSlotGuts::saveGame()
{
	//Base class
	bool8 result = SlotGuts::saveGame();

	if(result && !readytofinish)
	{
		//get the gamenum
		currentGameNum = (this->getSlotSpin(this->getSlotSpinCount()-1))->getGameNum();
		
		//And write what you can
		//In the icecream case, we can finish things off
		if(m_subGame->getData(SGIDX_BONUSGAME) == BGCASH)
		{
			//Cash
			if(createBonusGame(currentGameNum,10,0,BGCASH,0,(m_subGame->getData(SGIDX_CASHVALUE)*(m_info->creditValue))))
			{
				readytofinish = true;
			}
			else
			{
				result = false;
			}
		}
		else if (m_subGame->getData(SGIDX_BONUSGAME) == BGMUSIC)
		{
			//Grab bag
			if(!createBonusGame(currentGameNum,10,0,BGMUSIC,m_subGame->getData(SGIDX_NUMGOODPICKS),0))
			{
				result = false;
			}
		}
		else
		{
			result = false;
		}
	}

	return result;
}

